#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

// 定义设备名称
#define DEVICE_NAME "my_char_device"

// 定义设备号
static dev_t dev;
// 定义字符设备结构体
static struct cdev cdev;
// 定义类结构体
static struct class *my_class;
// 定义设备结构体
static struct device *my_device;

// 打开设备函数
static int my_open(struct inode *inode, struct file *file)
{
	printk(KERN_INFO "my_char_device: Device opened\n");
	return 0;
}

// 释放设备函数
static int my_release(struct inode *inode, struct file *file)
{
	printk(KERN_INFO "my_char_device: Device closed\n");
	return 0;
}

// 设备操作结构体
static struct file_operations fops = {
	.owner = THIS_MODULE,
	.open = my_open,
	.release = my_release,
};

// 模块初始化函数
static int __init my_module_init(void)
{
	int err;

	// 动态分配设备号
	err = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
	if (err < 0) {
		printk(KERN_ERR
		       "my_char_device: Failed to allocate major number\n");
		return err;
	}

	// 初始化字符设备
	cdev_init(&cdev, &fops);
	cdev.owner = THIS_MODULE;

	// 向内核添加字符设备
	err = cdev_add(&cdev, dev, 1);
	if (err < 0) {
		printk(KERN_ERR "my_char_device: Failed to add cdev\n");
		unregister_chrdev_region(dev, 1);
		return err;
	}

	// 创建类
	my_class = class_create(DEVICE_NAME);
	if (IS_ERR(my_class)) {
		printk(KERN_ERR "my_char_device: Failed to create class\n");
		cdev_del(&cdev);
		unregister_chrdev_region(dev, 1);
		return PTR_ERR(my_class);
	}

	// 创建设备并添加到系统
	my_device = device_create_with_groups(my_class, NULL, dev, NULL, NULL,
					      DEVICE_NAME);
	if (IS_ERR(my_device)) {
		printk(KERN_ERR "my_char_device: Failed to create device\n");
		class_destroy(my_class);
		cdev_del(&cdev);
		unregister_chrdev_region(dev, 1);
		return PTR_ERR(my_device);
	}

	printk(KERN_INFO
	       "my_char_device: Module initialized, major=%d, minor=%d\n",
	       MAJOR(dev), MINOR(dev));
	return 0;
}

// 模块退出函数
static void __exit my_module_exit(void)
{
	// 销毁设备
	device_destroy(my_class, dev);
	// 销毁类
	class_destroy(my_class);
	// 从内核移除字符设备
	cdev_del(&cdev);
	// 释放设备号
	unregister_chrdev_region(dev, 1);
	printk(KERN_INFO "my_char_device: Module exited\n");
}

module_init(my_module_init);
module_exit(my_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device driver");